package br.ucb.cm.main.ai.algorithm;

import java.util.Hashtable;
import java.util.Map;

import br.ucb.cm.board.bean.Location;
import br.ucb.cm.board.bean.Move;
import br.ucb.cm.board.bean.PieceMap;
import br.ucb.cm.board.util.BoardUtil;
import br.ucb.cm.config.GameInstance;
import br.ucb.cm.config.bean.PieceConfig;
import br.ucb.cm.main.ai.AIAlgorithm;
import br.ucb.cm.main.common.GeneralConstants.PlayerEnum;

public class MinimaxABAI implements AIAlgorithm{
	private Move bestMove;
	private PlayerEnum maximizingPlayer;
	private static final long MAX = - Long.MAX_VALUE;
	private static final long MIN = Long.MAX_VALUE;

	@Override
	public Move doMove(Map<Location, PieceConfig> pieceMap, PlayerEnum player) {
		maximizingPlayer = player;
		minimaxAlphaBeta(new PieceMap(pieceMap), player, MAX, MIN, GameInstance.getInstance().getNewGameConfig().getDifficulty());

		System.gc();
		
		if (bestMove == null){
			AIAlgorithm random = new RandomAI();
			bestMove = random.doMove(pieceMap, player);
		}
		return bestMove;
	}

	public long minimaxAlphaBeta(PieceMap pieceMap, PlayerEnum player, long alpha, long beta, int depth) {
		PlayerEnum opponent = player == PlayerEnum.PLAYER_ONE ? PlayerEnum.PLAYER_TWO : PlayerEnum.PLAYER_ONE;
		long value = (player == maximizingPlayer) ? alpha : beta;
		long reply = 0;
		Move maxMove = null;
		
		if(depth == 0 || pieceMap.hasWinner())
			return pieceMap.getPoints();

		for (Move move : BoardUtil.getAllMovesForPieceList(player, pieceMap.getPieceMap())) {
			PieceMap experimental = new PieceMap(new Hashtable<Location, PieceConfig>(pieceMap.getPieceMap()));
			experimental.setPoints(pieceMap.getPoints());
			
			performMove(experimental, move, player);

			reply = minimaxAlphaBeta(experimental, opponent, alpha, beta, depth - 1);
			if ((player == maximizingPlayer && reply > value) || (player != maximizingPlayer && reply < value)){
				if(player == maximizingPlayer){
					alpha = reply;
					value = reply;
					maxMove = move;
				} else {
					beta = reply;
					value = reply;
				}
				
				
				if (alpha >= beta)
					return value;
			}
		}
		
		bestMove = maxMove;
		return value;
	}

	public void performMove(PieceMap pieceMap, Move move, PlayerEnum player){
		int value = 0;

		if (pieceMap.getPieceMap().containsKey(move.getDestination())) 
			value = pieceMap.getPieceMap().get(move.getDestination()).getPoints().intValue();

		pieceMap.getPieceMap().remove(move.getSource());
		pieceMap.getPieceMap().remove(move.getDestination());
		pieceMap.getPieceMap().put(move.getDestination(), move.getPiece());

		value = (player == maximizingPlayer) ? value : (value * (-1));

		pieceMap.setPoints(pieceMap.getPoints() + value);
	}

}
